<!DOCTYPE html>
<html lang="en-us">
<head><head>
    <meta name="referrer" content="no-referrer"/>
    <meta name="google-site-verification" content="9vIieCe-Qpd78QOmBl63rGtIVbhY6sYyuxX3j8XWBA4" />
    <meta name="baidu-site-verification" content="LRrmH41lz7" />
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="google-site-verification" content="xBT4GhYoi5qRD5tr338pgPM5OWHHIDR6mNg1a3euekI" />
    <meta name="viewport" content="width=device-width, initial-scale=1">
    
    <meta name="description" content="后kubernetes时代概述">
    
    <meta name="keyword"  content="暴走的初号机, shinji3887, 暴走的初号机的网络日志, 暴走的初号机的博客, shinji3887 Blog, 博客, 个人网站, 互联网, Web, 云原生, PaaS, Istio, Kubernetes, 微服务, Microservice">
    <link rel="shortcut icon" href="/img/favicon.ico">

    <title>解读2017之容器篇：后Kubernetes时代 -同步率400%</title>

    <link rel="canonical" href="/post/after-kubernetest-genereation/">

    <link rel="stylesheet" href="https://lupeier.cn-sh2.ufileos.com/iDisqus.min.css"/>
	
    
    <link rel="stylesheet" href="https://lupeier.cn-sh2.ufileos.com/bootstrap.min.css">

    
    <link rel="stylesheet" href="https://lupeier.cn-sh2.ufileos.com/hux-blog.min.css">

    
    <link rel="stylesheet" href="https://lupeier.cn-sh2.ufileos.com/syntax.css">

    
    <link rel="stylesheet" href="https://lupeier.cn-sh2.ufileos.com/zanshang.css">

    
    <link href="/css/font-awesome.min.css" rel="stylesheet" type="text/css">
    
    
    <script src="https://lupeier.cn-sh2.ufileos.com/jquery.min.js"></script>
    
    
    <script src="https://lupeier.cn-sh2.ufileos.com/bootstrap.min.js"></script>
    
    
    <script src="https://lupeier.cn-sh2.ufileos.com/hux-blog.min.js"></script>
</head>
</head>

<nav class="navbar navbar-default navbar-custom navbar-fixed-top">
    <div class="container-fluid">
        
        <div class="navbar-header page-scroll">
            <button type="button" class="navbar-toggle">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="/">L&#39;s Blog</a>
        </div>

        
        
        <div id="huxblog_navbar">
            <div class="navbar-collapse">
                <ul class="nav navbar-nav navbar-right">
                    <li>
                        <a href="/">Home</a>
                    </li>
                    
                    <li>
                        <a href="categories/tech">tech</a>
                    </li>
                    
                    <li>
                        <a href="categories/tips">tips</a>
                    </li>
                    
                    <li>
                        <a href="/about">About</a>
                    </li>
                    
                </ul>
            </div>
        </div>
        
    </div>
    
</nav>
<script>
    
    
    
    var $body   = document.body;
    var $toggle = document.querySelector('.navbar-toggle');
    var $navbar = document.querySelector('#huxblog_navbar');
    var $collapse = document.querySelector('.navbar-collapse');

    $toggle.addEventListener('click', handleMagic)
    function handleMagic(e){
        if ($navbar.className.indexOf('in') > 0) {
        
            $navbar.className = " ";
            
            setTimeout(function(){
                
                if($navbar.className.indexOf('in') < 0) {
                    $collapse.style.height = "0px"
                }
            },400)
        }else{
        
            $collapse.style.height = "auto"
            $navbar.className += " in";
        }
    }
</script>




<style type="text/css">
    header.intro-header{
        background-image: url('https://lupeier.cn-sh2.ufileos.com/boat-control-design-1416649.jpg')
    }
</style>
<header class="intro-header" >
    <div class="container">
        <div class="row">
            <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
                <div class="post-heading">
                    <div class="tags">
                       
                       <a class="tag" href="/tags/kubernetes" title="Kubernetes">
                           Kubernetes
                        </a>
                        
                    </div>
                    <h1>解读2017之容器篇：后Kubernetes时代 </h1>
                    <h2 class="subheading"></h2>
                    <span  class="meta">Posted by 张磊 on Thursday, January 17, 2019
                        
                    </span>
					<br>
                </div>
            </div>
        </div>
    </div>
</header>




<article>
    <div class="container">
        <div class="row">

            
            <div class="
                col-lg-8 col-lg-offset-2
                col-md-10 col-md-offset-1
                post-container">

        		
                        <header>
                        <h2>TOC</h2>
                        </header>
                        <nav id="TableOfContents"></nav>
        		
        		<p>作 者</p>
<blockquote>
<p>张磊，浙江大学博士研究员，Hyper 项目成员，Kubernetes 项目资深成员与社区维护者。长期专注并活跃于容器集群管理与云计算数据中心领域，连续多次被微软授予该领域“最有价值专家（MVP）”称号。</p>
</blockquote>
<p>如果说 2017 年的容器技术圈子只能用一个关键词来概括的话，那一定非“Kubernetes”莫属。</p>
<p>从 2017 年 2 月，“Kubernetes”开始频繁登上各大技术媒体头条，来自不同维度不同渠道的商业分析和技术文章也纷至沓来。有趣的是，无论是官方报道还是个人评述，无论是直接还是委婉，无一不在透露着一个同样的信息：“Kubernetes 要赢！”</p>
<p>可是，描述这样一个连商业实体都没有的开源项目“要赢”，总是听起来有些奇怪。</p>
<p>“要赢谁？”</p>
<p>“为什么要赢？”</p>
<p>“赢了之后呢？”</p>
<p>我们不妨就从这个论断说起吧。</p>
<p>Kubernetes 赢在何处</p>
<p>如果说错失了 Big Data 时代的 Google 实在令人扼腕，那么 Container 时代的 Google 终于靠开源社区打了个翻身仗。虽然在最初的 lmctfy 项目（Google 自研容器）上依然栽了跟头，虽然同 Docker 公司共举容器编排大业的计划依然吃了闭门羹。但 Google 还是笑到了最后。</p>
<p>不过，Kubernetes 项目的发展绝非一帆风顺。它的前期只有一篇不温不火的 B 类会议文章 Borg 来站台，远没有“三大 paper”一举奠定大数据基石那么耀眼。而在它发布的之后，炙手可热 Docker 公司却始终拒绝同 Google 开展任何形式的合作。而与此同时，Mesos 等一票老牌调度系统的阴影则从一开始就让 Kubernetes 团队心有芥蒂。种种不利因素，再加上当时 Google 在 Kubernetes 上投入资源时的捉肘见襟，无论再怎么乐观，这个“要赢”的论断恐怕都不容易成为现实，</p>
<p>当然，如果不是 Google 找到了一个靠谱的盟友的话。</p>
<p>这位盟友有多靠谱？它是这个世界上唯一一家年盈利超 10 亿美元的开源技术公司。</p>
<p>Kubernetes 刚发起的时候，其核心的理念来自几位“Elder（元老）”的构想，他们大多是 Borg 和 Omega 项目的开发者或者架构师，一直专注于如何在没有 cloud 的场景下构建足够规模的通用 Infrastructure Layer 的实践，并且在这个领域摸索的过程中，这批技术人员也逐渐形成了一套创新性的设计理念，这些观点在 Borg 论文中曾经透露出了一些端倪，但真正全面揭晓还是依托于 Kubernetes 开源项目。所以如果大家回头去翻 Kubernetes 最早的一些 Issue 和 Design，其实都是一篇篇“小论文”，思路严谨，论证充分（废话连篇），这跟大多数开源项目早期的头脑风暴，或者围绕一个核心设计逐渐展开的做法，是有很大不同的。</p>
<p>另一方面，彼时的 RedHat 正苦于自家 OpenShift 被竞争对手碾压的境况。经典 PaaS 不能破局的困难，反倒让 RedHat 对 Docker 这个有望颠覆 PaaS 的项目格外上心。这样一个在操作系统领域积累深厚、资源充足、并且蠢蠢欲动以求变革的开源巨头，碰上了满脑子 Idea 却对全面推进 Kubernetes 心有余而力不足的 Google 团队，可谓一拍即合。2014 年 12 月，在 Google 正式发布 Kubernetes 项目不久，RedHat 即官方宣布与 Google 开展战略合作，全面投入 Kubernetes。在当时的一份官宣中，RedHat 以非常自信的姿态表达了对容器的“颠覆性”创新的认可，并大胆预言 Kubernetes 会在 2015 年后取得应用编排与管理领域的统治地位：</p>
<p>……（RedHat 的竞争对手们） 必须要认识到自研任何容器的局限性，尽早接纳 Docker 项目 …… …… （RedHat 的竞争对手们）必须要认识到没有人能够同 Google 在成规模的容器编排和管理领域里相抗衡 ……</p>
<p>谁曾想到，当年这套透露着几分“终于傍上大腿”的侥幸、甚至“托大”的说辞，现在看起来却几乎句句“实锤”。</p>
<p>这也是为何，Kubernetes 虽一直大幅受益于 Google 的声誉和名望，还长期拥有 Borg/Omega 团队的技术加持，但如果从技术实现上来审视，这个项目却称得上是半个 RedHat 项目。也正是凭借最初阶段“Google 赋予灵魂，RedHat 赋予实体”的策略，Kubernetes 才能够秉持着天马行空的设计思想的同时，稳扎稳打，然后一步步崛起于社区。</p>
<p>如今的 Kubernetes，既赢得了 GitHub 等众多明星用户的青睐，也受到了全世界所有公有云巨头的热捧，还硬生生把 Docker 公司逼到改旗换帅、彻底摒弃了以往“暴力不合作”的路线，如果用一个“赢”字来描述它现在的情形，倒也并不为过。不过，这个“赢”字背后的原因，又在哪里呢？</p>
<p>Rancher 的创始人梁胜博士最近有过一句评论，可谓道破天机：</p>
<p>时至今日，在容器技术领域依然有许多创新，只不过这些创新大多发生在 Kubernetes 以及 CNCF 生态系统中了</p>
<p>没错，容器技术圈的创新能力，在 2015 年后就已经逐渐转移到了 Kubernetes 生态，这是一个不争的事实，却也是一个曾经被忽视的变化。实际上，伴随着 DockerCon 越来越“boring”，Kubernetes 的专属生态 CNCF 基金会却开始风生水起的原因也正在于此。</p>
<p>而从技术的角度上看，Kubernetes 生态能取得这样的成功，依托的乃是一项其他竞争对手所不具备的核心能力：“使能用户二次创新“。</p>
<p>何谓“使能用户二次创新”？这其实是 Kubernetes 项目从开始设计之初就高度重视的一项关键诉求：</p>
<p>第一：从上层 API 到底层容器运行时，Kubernetes 工作流中的每个环节，都希望具备完善的可扩展性。</p>
<p>第二：Kubernetes 任何功能特性的设计和实现，都尽可能针对更通用的用户场景而非特定需求。</p>
<p>原生“使能二次创新”的技术基础，加上 Google 与生俱来的技术号召力，在加上 CNCF 基金会的整合和商业运作，以 Kubernetes 为核心所建立起来的这套容器编排生态，绝不比 Docker 公司最初建立起来的以容器为核心社区有任何逊色。再加上容器编排与管理的概念天生就更接近用户，Kubernetes 的理念很快被社区接纳乃至追捧，也是情理之中。</p>
<p>一个直观的例子就是 CoreOS 的 Operator 项目。我们知道，在 Kubernetes 里部署任务，经常使用的是 Deployment（Replication）来管理多个副本组成集群。但如果我们这次要部署的任务比较特殊，它的集群需要在增 / 删副本之后 / 之前做手动的运维操作呢？各种数据库集群就是最典型的例子。而 Operator 实际上是个用户自己编写的管理器，通过编程的方式把“运维”逻辑写进了管理器的代码当中。</p>
<p>但关键在于，这个管理器的编写过程是完全“无脑”的，无非就是复制粘贴官方模板、然后填充自己的运维逻辑而已。这是因为 Operator 是构建于 Kubernetes 的 CRD（自定义 API 资源）特性之上的，这个特性的目的就是允许并帮助用户自己编写一个可以与系统 etcd 交互的、Kubernetes 风格的 API 资源管理器，并无缝地衔接到 Kubernetes 的核心 API 当中。</p>
<p>这个设计看起来很很直白，但是却解决了一个长期以来困扰系统级开源项目的难题：用户对项目的 API 不满意怎么办？</p>
<p>在过去的实践中，原封不动使用开源项目的场景是非常少见的，更常见的情况是用户把开源项目的 API 修改的面目全非。但在 Kubernetes 的场景下，用户的自定义 API 和原生 API 可以友好共处，统一对外服务，而且不会随着 upstream 变更而分家。这是保证 Kubernetes 社区完整性和被接纳程度的一个核心手段。</p>
<p>更为重要的是，有了这些标准化的扩展性 API，用户就可以发挥自己的能动性，在 Kubernetes 之上构建出更多的扩展，甚至把这些扩展再交还给社区中的其他用户推广和使用。正如 CoreOS 的 Operator，现在已经成为了社区运维有状态应用的一大法宝。</p>
<p>当然，“二次创新”的例子远不止于此。</p>
<p>2017 年 5 月 24 日，Lyft，IBM 联合 Google 共同宣布了 Istio 项目，一举撼动了微服务这个以往“光说不练”的“花架子”领域。Istio 的核心思想，乃是借助一个 proxy 来接管容器里业务的进出流量，从而通过在 proxy 上的控制操作来完成应用流量的切分、访问授权、策略配置等一些列微服务治理功能。可以看到，这里有一个核心问题是：如何保证每一个需要治理的容器都绑定这样一个 proxy 呢？</p>
<p>解决这个问题的手段就是 Pod。作为 Kubernetes 里的核心概念和原子调度单位，Pod 是一组亲密耦合的容器集合，容器之间共享同一 Network Namespace，显然，Istio 框架中的 proxy 和业务容器正属于这样的耦合关系。但这还不是关键所在，这里最棘手的问题在于，Istio 要做的是一个非侵入型的微服务框架，不可能要求用户在自己的部署文件中每次都额外定义一个 proxy 容器。怎么办？</p>
<p>答案还是借助 Kubernetes。Kubernetes 中有一个叫 Initializer 的扩展机制，允许用户在不修改业务 Pod 部署描述前提下，请求 Kubernetes 为业务 Pod“自动注入”并启动一个预先定义号的容器。在 Istio 里，这个自动注入的容器正是前面不断提到的 proxy：Envoy（Lyft 自研的高性能服务代理）。</p>
<p>可以看到，通过组合 Initializer 等一系列 Kubernetes 标准 API，用户可以优雅地实现很多以往繁琐或者困难的分布式系统的构建工作：就比如 Istio 里这套 Spring AOP（面向切面编程）风格的组合方式。也正是因为有了这种标准化的实现手段，用户基于 Kubernetes 的“二次创新”才有可能再次交还给 Kubernetes 社区，从而碰撞出更多的创新火花和更新颖的用户案例。最终，不断激发出的创新开始吸引了更多人力和资本的进入，而资本与生俱来的促进作用就会推动这个社区的更强势的扩张。这种“开源 - 社区 - 商业”互相促进而构建出来的正向激励循环，正是 Kubernetes 生态在过去一年里“势不可挡”的重要原因。</p>
<p>回想在 Kubernetes 刚发布的时候，甚至在 2017 年初，Kubernetes 的 Pod 以及 Pod 所体现出来的“解耦容器关系”的设计模式，依然时常被质疑为“用处不大”或者“过度设计”，然后现在回头来看 Istio 项目的炙手可热，我们确实要感慨“技术视野”的培育绝非一朝一夕。</p>
<p>从利用 CNI、CRI 等一系列良好设计的通用接口来实现不同类型、不同功能的网络和容器运行时，到使用 API Aggregation 扩展 Kubernetes API Server 从而支持自定义资源监控格式并以此来做 Auto-Scaling，Kubernetes 生态之中类似的“二次创新”的例子已然不胜枚举。依托于这种原生地鼓励用户发挥自己聪明才智的先进理念，在 2018 年，我们有足够的理由相信“二次创新”将继续成为 Kubernetes 生态中的一大关键词，各种基于 Kubernetes 可扩展能力的创新工作将成为社区的常态，甚至成为更多团队“一战成名”的不二法宝。</p>
<p>在未来，已经争取到领先地位的 Kubernetes 项目的进化重点，将逐步转移到安全性、稳定性、多租户能力、规模和性能优化、可扩展性设计等更多横向功能的升级上面。另外，将更多的非核心功能从主干代码中移除也将是未来一段时间 Kubernetes 社区的主要工作之一。</p>
<p>2017 年里，随 client-go、apimachinery 等 API 库的独立，已经为 CRD 等可扩展性功能的实现带来了极大的便利，而将来诸如部署工具 kubeadm，内置的各种 Cloud Provider，内置的 rkt 集成，各种各样的 volume plugin 等代码，也都将逐步迁移到它们单独的库中维护，这将有希望大大降低 Kubernetes 主库的复杂度和维护难度。</p>
<p>另一方面，Kubernetes 可扩展性上的另一个重要设计 CSI（Container Storage Interface）也已经发布。这意味着不久的将来，就如同容器运行时一样，容器持久化存储方案也将不必再跟 Kubernetes 的核心代码耦合，Kubernetes 将使用统一的 gRPC 接口在完全独立的控制逻辑中维护容器存储卷（volume）生命周期。这个设计也很有可能会刺激容器存储领域更多的创新工作和更多的存储选择出现在 Kubernetes 社区当中。而包括 KataContainers 在内的虚拟化容器运行时，也将受益于存储解耦带来的、完全不同于现有容器存储设计的高性能的持久化存储方案。</p>
<p>在接下来的集群管理能力上，目前最大 5000 个节点的支持能力已经能够满足大多数用户的生产需求，而 IPVS Service 的引入也有很大希望能解决以往纯 iptables Service 引发的大规模集群中性能额外损耗问题。而在调度层面，默认调度器的可配置规则已经大幅增加，调度优先级和抢占技术也已经进入了默认调度器的 alpha 功能当中。而通过灵活配置亲密 / 反亲密关系、Taint/Toleration 规则，Kubernetes 的使用者已经能够解决绝大多数生产环境中的运维和调度需求。</p>
<p>在多租户与安全能力上，Kubernetes 项目终于弥补上了这部分的短板。RBAC（基于角色的访问控制）功能目前已经成熟应用于很多基于 CRD 的 Kubernetes 外部扩展上面，Secret 存储的加密也已经实现，集群部署中的节点通信加密配置也成为了默认功能。而在社区中，更完善的“强多租户”设计也第一次被提出，以便真正满足多租户环境下的集群管理需求。不过需要指出的是，Kubernetes 的角色定位依然是 Layer 0（Infrastructure Layer），更倾向于对上提供必要的多租户支持 API 和规范而不是实现完整的多租户模型。后者还是需要依靠 Layer 1（Service Layer）来自己完成。</p>
<p>2017 年也是人工智能技术席卷全球的一年，Kubernetes 在其中也扮演了推波助澜的作用。在与之相对应的硬件加速器（Hardware Accelerator）功能的设计上，Kubernetes 社区在 Google，NVIDIA 和 Intel 的牵头下发布了 Device Plugin 来允许用户自己编写自定义的、自发现的高性能硬件资源描述，并且以此为基础，将支持 NUMA，InfinitiBand，FPGA 等硬件框架的设计纳入了路线图。随着 Kubeflow 等项目的发布，不难预料到，Kubernetes 在新的一年里会继续加大同人工智能社区合作，向成为机器学习领域支撑大规模分布式训练和 AI 服务的默认框架这一目标上不断挺进，而在此过程中，各家 vendor 在 Kubernetes 社区中进行技术上的角逐，亦将成为这个领域的主旋律之一。</p>
<p>随着 Kubernetes 项目的逐渐稳定，其开发迭代周期也将有所放缓，将目前每 3 个月一次 release 周期延长已经被提上讨论日程。与此同时，随着社区自动化管理能力（bot）的提高和 SIG（Special Interest Group）组织的进一步完善，现有社区成员的写权限回收也是将来可能发生的大概率事件。这些都是 Kubernetes 社区逐步走向成熟的标志性里程碑。</p>
<p>容器运行时的二次繁荣</p>
<p>2017 年，Kubernetes 引领了容器编排与管理领域的蓬勃发展，而与此同时，另一个很有意思的现象则是容器运行时（Container Runtime）迎来了一次难得的二次繁荣。</p>
<p>一般来说，伴随着容器编排领域的迅速发展和成熟，容器运行时技术一定会因为被上层编排框架所屏蔽而逐渐淡出用户视野。事实上，这也正是 Docker 公司自成立以来的心病：光有一个容器运行时 Docker，并不足以吸引用户真正投入到有价值的商业产品（比如 PaaS）上来，更何况容器技术本身又是一个门槛相对不高的组合性创新成果，不能形成长期有效的技术壁垒。这个事实，也正是 Docker 公司一定要强推 Swarm 和 SwarmKit 等项目，以及 Mesosphere 曾短暂取得瞩目的一个主要原因。</p>
<p>当然，在 Kubernetes 依托社区和强大的创新能力崛起之后，容器运行时和它背后的主体的淡出便成了不可避免的宿命。这也是为什么我们会看到 Docker 公司会宣布将它的开源项目改名为 Moby，这其实是它自己宣布将要放弃在开源社区中继续同 Kubernetes 和 CNCF 社区对抗的重要信号。这也是为什么我们会看到 containerd 和 rkt 被接连捐献给 CNCF 基金会：各类容器运行时的历史使命已经走向尾声了。</p>
<p>但是历史总有意外。Kubernetes 的扩展性设计中一项核心功能的确立，却为容器运行时的创新者带来了新的机遇，这就是 CRI（Container Runtime Interface）。</p>
<p>CRI 的诞生还得追溯到容器运行时第一次繁荣、也就是容器理念第一次席卷技术圈的时候。彼时，Docker 公司手持 Docker 项目大杀四方、是当之无愧的容器技术领导者。而 CoreOS 公司在选择拥抱 Google 和 Kubernetes 的同时，则发布了 rkt 以制衡 Docker，以希望维护自己在容器技术上的话语权。这两位，再加上 RedHat，他们在容器运行时领域的合作与竞争，直接推动了 OCI 这一容器技术标准的诞生。但实际上我们不难看到，Docker 公司在容器运行时领域所占据的绝对主导地位，以及 OCI 本身对 Docker 公司商业利益的不友好意味，使得 OCI 长期以来并没能发挥出“标准”所应起到的推动和整合作用。</p>
<p>也正是在这个阶段，以 Intel ClearContainer 和 Hyper 为代表虚拟化容器技术，则开始从安全和多租户角度进入到开发者的视野。一时间，容器运行时领域可谓熙熙攘攘，不胜热闹。</p>
<p>而在 Kubernetes 发布之后，很多机敏的技术人员其实已经嗅到了其中的机遇。在 Kubernetes 未来有大概率会成功的前提下，谁能在 Kubernetes 内置的容器运行时中抢占到一个位置，谁才有可能在将来的容器技术圈子中争取到一席之地。所以很快，CoreOS 公司通过政治和技术双管齐下的努力下，rkt 成功跻身为 Docker 之后第二个被 Kubernetes 支持的容器运行时。但也正在这时，一些连锁反应式的问题也被激发出来。</p>
<p>一方面，彼时的 Kubernetes 羽翼未丰，并没有强势到能直接帮扶起 rkt 这个相对弱势的容器运行时的地步，更何况当时的 Docker 项目正突飞猛进，没有给同质的 rkt 留下任何喘息和反击的机会。所以虽然很早就进入了 Kubernetes 体系，rkt 却一直处于少有用户问津的尴尬地位。</p>
<p>而另一方面，在当时快速迭代、完全没有稳定的 Kubernetes 尤其是 kubelet 组件中，额外引入的 rkt 运行时其实带来了大量的维护工作，并且这些工作很多时候还要依赖于 CoreOS 的介入才能解决，这无疑给 Kubernetes 团队带来了很大的压力。</p>
<p>与此同时，Kubernetes 团队本身并不希望锁定在 Docker 容器之上。Docker 公司不断推进 Swarm 项目的决心，很难让人对继续使用这样一个唯一的、不稳定的、将来甚至可能会变成一个 PaaS 的“容器”感到放心。</p>
<p>在这样的背景下，适逢 Kubernetes 团队也开始尝试逐步在项目中引入虚拟化容器技术，能不能提供一个通用的、与下层容器运行时无关的接入层来无缝对接上述所有容器运行时，就成为了当时 Kubernetes 能否更进一步关键所在。更重要的是，这也是 Docker 的软肋之一。由于显而易见的原因，Swarm 体系并没有动力去支持任何非 Docker 之外的容器运行时，而另一方面，彼时的 OCI 话语权不济，并不能发挥对接其他容器运行时的作用，这就意味着 Kubernetes 项目会成为对接非 Docker 容器运行时的唯一出路。</p>
<p>就这样，一套由 Google，Hyper 和 CoreOS 共同主导的、以 Kubernetes 项目为核心的容器运行时接口的设计，应运而生。</p>
<p>CRI 的及时发布，使得 Kubernetes 团队在后续 SwarmKit 等事件中可以处变不惊。而它的诞生，也直接推动了容器运行时这原本应该逐步淡化的领域焕发了第二次繁荣。</p>
<p>cri-o 与 cri-containerd</p>
<p>这次繁荣的第一个标志性的事件，是 runC 容器运行时 cri-o 的发布。</p>
<p>cri-o 的初衷非常直白，既然现在 Kubernetes 可以借助 CRI 对接任何容器运行时甚至虚拟机，那么我们自然会想到，为什么不直接把 runC 封装成一个 CRI 的实现呢？这样不就可以绕过现有 Docker 容器的大部分机制而直接操作 Linux 容器了么？</p>
<p>所以，不同于 Docker，除了用来响应 CRI 的 gRPC server，cri-o 并不需要额外的 daemon 组件来维护 Linux 容器。CRI 的 API 调用在这里被直接翻译成对 runC 的操作命令，然后在宿主机上创建并启动 runC 容器。不难看出，这个工作流其实跟 containerd 的功能是基本一致的，但有意思的是，cri-o 的发起者 RedHat 并没有使用 containerd 而是重新造了轮子。这其中，containerd 的实际维护者是 Docker 公司恐怕是主要的考量因素之一。</p>
<p>实际上，在 Docker 公司决定打造自己的封闭生态之后，RedHat 就跟 Docker 公司走向了对立的一面。毕竟相比 Google 专注于公有云业务而不太在意企业及市场，Docker 公司随后发布的每一项产品（项目），却都在不同领域实实在在争抢着 RedHat 的蛋糕。作为曾经一起同推进容器技术的“兄弟”，如今“分手”后的 RedHat 对 Docker 公司的负面态度是可想而知的。所以，cri-o 在某些实现细节上透露出来的一些偏执，也是这种思想指导下的必然产物。从最初放出言论要“fork Docker”，到现在 cri-o 的实际落地，RedHat 在容器运行时领域的志向目前都压在这个项目之上。这也是为何 RedHat 的宣传机器在 2017 年 可谓开足了马力，连 Kubernetes 首席布道师 Kelsey Hightower 也曾短期被“攻陷”过。</p>
<p>然而，开源社区里最有意思的事情也莫过于此。就在 cri-o 几乎要以下一代 Kubernetes 默认容器运行时的身份粉墨登场之时，Google 和 IBM 以及 containerd 的维护者们却默默的上线了 cri-containerd 项目。这个项目的思路更加显而易见：鉴于 containerd 已经捐给了 CNCF，现在只要在其基础上略微封装，就可以为 Kubernetes 打造一个 Docker native 的、身份中立的 CRI 实现。相比 cri-o 每个 release 都要推广一番的风风火火，cri-containerd 的进展可谓低调，仅在最近的 DockerCon 上小幅亮相了一次，并且期间一直与 cri-o 保持的良好的合作关系（比如共同维护 lib）。但低调并不意味着不作为，2017 年底，cri-containerd 项目悄无声息地开始了与 containerd 项目的合并计划，这意味着很快 containerd 本身将会原生支持 Kubernetes CRI。</p>
<p>CRI 的成功我们有目共睹，但 Kubernetes 下一代默认容器运行时目前却尚无定论。Kelsey Hightower 一向不太“待见”Docker，他的成名作“Kubernetes the Hard Way”在短暂试用 cri-o 后目前还是切换到了 cri-containerd 上。不过这也并不足以说明所有问题，至少在未来一段时间内，“No Default”还是可以继续作为这一领域的官方说辞。</p>
<p>不过，cri-o 本身的崛起，侧面说明了“得编排者得天下”是目前容器运行时领域进一步发展的正确思路。而也正是这个思路的推动下，我们得以见证了这次技术繁荣的第二个标志性事件。</p>
<p>Kata！Kata!</p>
<p>这个事件，正是 Hyper runV 同 Intel ClearContainer 的合并。合并之后的项目以 KataContainers 命名并托管于中立基金会，为虚拟化容器技术路线之争画上了句号。</p>
<p>实际上，在 Hyper 推出了 runV 技术之后，部分敏锐的技术人员就迅速开始了往 Kubernetes 推进基于 runV 的虚拟化容器技术的的集成工作。相比于 Swarm 体系的封闭和 Mesos 社区的后知后觉，Kubernetes 项目从一开始就展现出来的技术远见，使得这个选择倒并不意外。而这次技术行为的直接结果，则是推动了 CRI 这一关键特性的诞生和落地：又是一个典型的社区“二次创新”然后再反哺社区的故事。在这个过程中，kubernetes/frakti 项目作为虚拟化容器运行时的官方 CRI 实现，正是推动这项技术进入 Kubernetes 生态核心的关键一步。</p>
<p>不过，相比于 Linux 容器领域的 Docker 项目的一枝独秀，虚拟化容器技术则有一个困扰社区许久的问题，那就是几乎同期发布的 Intel ClearContainer 项目一直以来跟 runV 处于重合位置。尽管在项目的后期，Intel 和 Hyper 团队已经开始共同维护很多公有的子项目，但开源社区的掣肘关系依然牵制了虚拟化容器技术进入容器生态核心的步伐。</p>
<p>不过，明智的是，runV 并没有固执地在容器 API 层面同 Intel 开展类似 Docker 和 rkt 之间的竞争，而是把原生接入 Kubernetes 当成了第一要务，希望借助上层编排框架来为容器运行时发声。这个策略无疑改变了社区对虚拟化容器技术在整个生态中所处位置的看法。事实上，相比于我们所熟知的硬件级别隔离和容器安全这样的常识，虚拟化容器技术的独立内核特性为 Kubernetes 支持遗留应用和传统业务带来的巨大的想象空间，才是这种技术最大优势所在。</p>
<p>尤其是伴随着 2017 年后期“强多租户”概念被引入到 Kubernetes 社区，能够从容器运行时层就开始进行租户隔离的设计已经成了一种刚性需求。没有虚拟化级别的隔离能力和独立内核来保证业务的多样性，“强多租户”基本无从谈起。试想一下，在一个真正的多租户云数据中心里，有的租户的应用是 Windows 的，有的是 Linux 的，除非做低效的静态划分，常规 Linux 容器又该如何应对这样的需求呢？</p>
<p>KataContainers 项目的出现，把刚刚崭露头角的虚拟化容器技术推向了一个新的阶段。作为 OpenStack 基金会力图革新后发起的第一个项目，托管于该基金会下面的 KataContainers 却不必遵守 OpenStack 社区任何现有的规范，其自由度和改革力度，可见一斑。</p>
<p>而这次合并的最终促成虽然被 OpenStack 基金会抢了先机，但 CNCF 基金会则开始从 OCI 入手，试图将 KataContainers 的运行时再纳入到 OCI 的范畴之中。我们有理由相信，在两大基金会的通力合作之下，KataContainers 的前景非常光明。</p>
<p>不过，更为重要的是，以 KataContainers 为代表的虚拟化容器技术在云计算领域的探索，正有意无意地打开了公有云的一个新篇章。</p>
<p>ACI，Fargate 与“Serverless 容器云”</p>
<p>在 runV 容器发布之后，为了验证虚拟化容器对公有云带来的变化，一个名为 hyper.sh 服务同步上线并随后迅速霸榜了 HackerNews 头条。这个服务的创新之初在于，虽然它的整个技术栈都基于 Kubernetes，但是它却不对外暴露任何 Kubernetes API，也没有提供任何操作 console，而是让用户用本地的“hyper run ”指令来在云端创建和启动容器。由于使用了虚拟化容器技术，这个工作流里完全不需要虚拟机的介入，所有租户的容器直接运行在裸物理机集群当中。</p>
<p>虽然看起来简单，但这个设计的本质，却提供了一种容器云的 Serverless 的设计思路。在这个“无服务器”云的设计中，云的用户完全不必学习任何 Kubernetes 或者云平台 API 或者文档，仅靠开发者所熟悉的本地容器操作就可以完成作业的云端部署，然后按秒计费。</p>
<p>而在 2017 年，这种颇有远见的容器云 Serverless 开始得到了公有云巨头的青睐。这一次的始作俑者正是近年来在云服务领域出手“稳”、“准”、“狠”的 Microsoft。2017 年 7 月 26 日，Microsoft Azure 团队宣布了 ACI（Azure Container Instance）服务的发布，其通过“az container create”创建容器的思路，与 hyper.sh 如出一辙，并且同样屏蔽了所有下层的 PaaS 和 IaaS 概念然后按秒计费。一石激起千层浪，国外容器技术圈子对这种服务的讨论迅速成为了当时的技术头条。有人说它是 AWS Lamda 的有力竞争者，也有人说这才是 Serverless 服务的终极形态。</p>
<p>紧接着，在 2017 年 11 月，堪称全球云计算技术风向标的 AWS re:Invent 大会上，AWS 高调宣布了同类型服务 Fargate 的诞生，把 Serverless Container Cloud 的理念推向了新的高潮。作为回应，Microsoft 则联合 Hyper 发起了 virtual-kubelet 项目，旨在定制一套标准，允许云提供商把自己的 Serverless Container Cloud，以 kubelet API 的方式接入到任意的 Kubernetes 集群中作为一个特殊的节点而存在，从而轻松实现一个基于 Kubernetes 的混合云。目前，AWS、甚至 OpenStack 都已经加入这个项目开始贡献自己的实现，对应的基金会和开源生态正迅速形成。不出意外，很快 Google、国内的阿里云等巨头，也会推出类似的 Serverless Container Cloud 服务，并且加入到 virtual-kubelet 项目当中。</p>
<p>Serverless Container Cloud 服务备受欢迎的本质，乃在于公有云计算所服务的用户，尤其是广大的开发者群体，对于追求“简单高效”的热情其实是非常高涨的。对于他们来说，在各种设计拙劣的云管理界面上进行凌乱的鼠标操作，绝对不如在键盘上敲打本地命令来的舒服。这种微妙的体验变化，正如同 git 对比 SVN，Docker 对比 OpenStack。更为重要的是，这种服务形态也正符合了 Kubernetes 技术继续发展的正确路线：Kubernetes 所要扮演的角色，乃是取代传统的 Infrastructure Layer 并鼓励技术人员进行上层的“二次创新”，而并不是直接面对最终用户（实际上 Kubernetes 本身的声明式 API 也是对运维而非开发友好的）。真正为最终用户提供云服务的，很大概率应该是构建于 Kubernetes 之上的、更加简洁高效的服务型 API，而 Serverless，尤其是 Serverless Container Cloud 的设计，正是这种需求下最为贴切的实现方式之一。</p>
<p>不难预料，在新的一年，基于 Kubernetes 之上构建出来的创新型 Serverless 服务（当然也包括 OpenFaaS 等优秀的 Function），将会是大小云计算提供商进一步角逐的一个关键领域。相比之下，曾经在国内外普遍开花的、以直接售卖 Kubernetes 集群为核心的各种“CaaS”，将会沉寂许多。</p>
<p>Docker Inc 的未来</p>
<p>毫无疑问，2017 年的 Docker 公司依然是容器圈子里的主角。只不过这一次，波澜之中的 Docker 公司的确并不好过。</p>
<p>从 2017 年 4 月 Docker 项目毫无征兆地改名为 Moby 开始，Docker 公司顶着巨大的争议，逐步完成了开源技术创新公司到商业公司的转变，也开始正视长期以来同 Kubernetes 社区竞争所带来的极其不利的商业局面：伴随着 Kubernetes 项目的成功，Swarm 已成为明日黄花，曾一度承载着新希望的 SwarmKit 也渐渐淡出社区视野。2017 年 10 月，在 DockerCon EU 上，Docker 公司官方宣布下一版本的 Docker EE 中将全力拥抱 Kubernetes，标志着持续了近三年之久的容器编排之争彻底落下帷幕。紧接着，所有纷争的始作俑者、曾经携 Docker 对抗整个容器社区的 Solomon Hykes 也宣布自己“角色转变”，不再负责 Docker 产品的具体技术事宜。</p>
<p>曾经纷纷扰扰的容器圈子，竟然一夜之间尘埃落定，个中滋味，不免让人心生惆怅。Docker 公司和 Solomon 的经历可能不算是传奇，但也绝对能够在云计算历史中留下了浓墨重彩的一笔。我们甚至会不时想象，如果当初 Solomon 没有去做 Swarm，而是选择同 Google 合作共举 Kubernetes，如今的 CoreOS 还会不会活着？如今的 Docker 公司又是什么样子？</p>
<p>历史难做假设。</p>
<p>但是 Docker 公司的未来却依然是光明的。</p>
<p>在积极拥抱 Kubernetes 社区之后，Docker 公司正走向正确的轨道。大家不要忘记，在迎合开发者社群和技术微创新这两个关键手段上，Docker 公司的实力绝不容忽视。2018 年初，Docker Mac 集成 Kubernetes 的版本正式发布，并立刻在开发者群体中掀起了轩然大波。在 Mac OS 上如此流畅启动和运行 Kubernetes 的体验，在这么短的时间内就被 Docker 公司带到了开发者手里，这其中体现出来的技术能力与产品理念，正是将来 Docker 公司继续立足的核心所在。当然，Docker 公司最终的成功，依然取决于其商业产品能否赢得重量级客户的青睐，在这一点上，Kubernetes 的坚定盟友 CoreOS 已然占尽先机并且完成了转型。但是 Docker 公司在容器领域不俗的创新能力和产品积累其实是有增无减，其产品线也更完整，在开发者群体中的基础也更雄厚，这样一个人气与技术兼备的创业公司的未来，绝不见得会像某些文章中描述的那样一片哀鸿。这一点，我们不妨拭目以待。</p>
<p>国 内</p>
<p>相比于过去默默无闻，2017 年的国内容器技术玩家终于得意发声，而且“不鸣则已，一鸣惊人”。阿里集团在双 11 过后，高调发布了源自其内部容器 T4 的开源项目 Pouch，并迅速成为了当时的技术热点。事实上，早在 Docker 和 Kubernetes 技术如火如荼的 2015 年，业界就发出过疑问：在此领域积累深厚（百度有 Matrix，阿里有 T4）的国内的互联网巨头为何迟迟不见动作？</p>
<p>好在厂商会迟到，但技术不会。Pouch 的发布，也正是前面提到的“2017 年容器运行时技术二次繁荣”的又一例证。在 Docker 公司逐渐式微、rkt 几乎退役的档口，Kubernetes 的崛起和 CRI 的成熟正在为所有的容器运行时玩家带来全新的机会。从代码上看，Pouch 并非“Docker fork”，而是利用类似技术进行的全新实现。从功能上看，Pouch 原生接入了 runV 来提供多样化的隔离机制，内置“富容器”能力以满足不同的业务场景，打包了 Dragonfly 来实现高效的镜像分发，这意味着这套技术栈从底自上有着同 Docker 整体不一样的业务考量。</p>
<p>但另一方面，如今的时间点不同与 2015 年，用户的关注点已经从容器运行时转移到了上层容器编排管理的服务能力。而作为近来 Linux 容器的第三个实现（cri-o 只支持 Kubernetes，不能算作完整的容器实现），尽管功能上有所差异，但 Pouch 仍然难免会陷入同质竞争的不利局面。不过需要指出的是，阿里集团接下来亦在酝酿其内部集群管理系统 Sigma 项目的开源工作，并且会积极地将 Sigma 纳入到 Kubernetes 的现有生态当中，这就为 Pouch 未来的前景增添了一层有趣的砝码。毕竟，Pouch 本身在 Docker 的优势地位中突围可以说困难重重，但正如前面所提到过的，如果能够借助上层容器编排能力重新表达这一容器运行时的关键作用，那这套技术方案的应用前景和接纳难度很可能会发生变化。这也正回到了我们最开始谈到“Kubernetes 赢在何处”时所作出的阐述：Kubernetes 社区通过从技术和生态双重层面上使能用户二次创新的做法，必将推动这个生态走向一个更加繁荣而有意义的新阶段。</p>
<p>总 结</p>
<p>“任何一个被浓厚的商业兴趣所充斥的开源社区，最后都难免走向有毒的方向”&ndash; Solomon Hykes</p>
<p>2017 年，曾经的弄潮儿 Docker 公司在巨大的争议中终于完成了向商业公司的重要转变，也宣告了由 Kubernetes 社区所主导的、全新的容器生态正式拉开序幕。在回顾 Kubernetes 如何赢得这次竞争的同时，我们应该意识到容器运行时“二次繁荣”的短暂窗口正在为我们带来新的机遇。与此同时，容器公有云的形态正在悄然发生变化，伴随着这次变革而存在的，固然有风险，但也有很可能会催生出新的云计算赢家甚至独角兽。</p>
<p>最为重要的是，伴随着 Kubernetes 社区的日益壮大，如何避免这个生态陷入 Solomon 所警告的“有毒”陷阱，恐怕很快就会成为摆在这个社区所有参与者面前的一道难题。是的，是所有参与者都对此负有责任，而绝不仅仅是 CNCF 或者 Google 就有能力独自解决的一次危机。</p>

        
                
        
              <hr>
              <ul class="pager">
                  
                  <li class="previous">
                      <a href="/post/kubeadmin-create-cluster/" data-toggle="tooltip" data-placement="top" title="使用kubeadm快速搭建单机kubernetes 1.13集群">&larr; Previous Post</a>
                  </li>
                  
                  
                  <li class="next">
                      <a href="/post/create-eureka-ha-cluster/" data-toggle="tooltip" data-placement="top" title="搭建eureka高可用集群">Next Post &rarr;</a>
                  </li>
                  
              </ul>
  
              

<div id="gitalk-container"></div>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.css">
<script src="https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.min.js"></script>
<script src="/js/md5.min.js"></script>
<script>
	const gitalk = new Gitalk({
	  clientID: 'aff2580d8cc58af83367',
	  clientSecret: '747547f5f87fcc5145b847ab76a498d7e501319f',
	  repo: 'comment',
	  owner: 'shinji3887',
	  admin: ['shinji3887'],
	  id: md5(location.pathname),      
	  distractionFreeMode: false  
	})

	gitalk.render('gitalk-container')
</script>


            </div>
            
            <div class="
                col-lg-8 col-lg-offset-2
                col-md-10 col-md-offset-1
                sidebar-container">

                
                <section>
                    <hr class="hidden-sm hidden-xs">
                    <h5><a href="/tags/">FEATURED TAGS</a></h5>
                    <div class="tags">
                     
                    
                        
                            <a href="/tags/api-gateway" title="api-gateway">
                                api-gateway
                            </a>
                        
                    
                        
                    
                        
                            <a href="/tags/cloud-native" title="cloud-native">
                                cloud-native
                            </a>
                        
                    
                        
                            <a href="/tags/devops" title="devops">
                                devops
                            </a>
                        
                    
                        
                            <a href="/tags/docker" title="docker">
                                docker
                            </a>
                        
                    
                        
                    
                        
                    
                        
                    
                        
                    
                        
                            <a href="/tags/istio" title="istio">
                                istio
                            </a>
                        
                    
                        
                    
                        
                            <a href="/tags/kubernetes" title="kubernetes">
                                kubernetes
                            </a>
                        
                    
                        
                            <a href="/tags/microservice" title="microservice">
                                microservice
                            </a>
                        
                    
                        
                    
                        
                    
                        
                    
                        
                    
                        
                            <a href="/tags/restful" title="restful">
                                restful
                            </a>
                        
                    
                        
                    
                        
                            <a href="/tags/servicemesh" title="servicemesh">
                                servicemesh
                            </a>
                        
                    
                        
                            <a href="/tags/spring-cloud" title="spring-cloud">
                                spring-cloud
                            </a>
                        
                    
                        
                            <a href="/tags/vue" title="vue">
                                vue
                            </a>
                        
                    
                        
                    
                        
                    
                    </div>
                </section>

                
                <hr>
                <h5>FRIENDS</h5>
                <ul class="list-inline">
                    
                        <li><a target="_blank" href="https://skyao.io/">小剑的博客</a></li>
                    
                        <li><a target="_blank" href="https://zhaohuabing.com/">huabing的博客</a></li>
                    
                        <li><a target="_blank" href="http://blog.didispace.com/">程序猿DD的博客</a></li>
                    
                </ul>
            </div>
        </div>
    </div>
</article>




<footer>
    <div class="container">
        <div class="row">
            <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
                <ul class="list-inline text-center">
                   
                   <li>
                       <a href="" rel="alternate" type="application/rss+xml" title="L&#39;s Blog" >
                           <span class="fa-stack fa-lg">
                               <i class="fa fa-circle fa-stack-2x"></i>
                               <i class="fa fa-rss fa-stack-1x fa-inverse"></i>
                           </span>
                       </a>
                   </li>
                   
                    
                    <li>
                        <a href="mailto:18016380795@163.com">
                            <span class="fa-stack fa-lg">
                                <i class="fa fa-circle fa-stack-2x"></i>
                                <i class="fa fa-envelope fa-stack-1x fa-inverse"></i>
                            </span>
                        </a>
                    </li>
		    
                    
                    
                    
                    

                    

		    
                    
                    <li>
                        <a target="_blank" href="/link%20of%20wechat%20QR%20code%20image">
                            <span class="fa-stack fa-lg">
                                <i class="fa fa-circle fa-stack-2x"></i>
                                <i class="fa fa-wechat fa-stack-1x fa-inverse"></i>
                            </span>
                        </a>
                    </li>
		    
                    
                    <li>
                        <a target="_blank" href="https://github.com/shinji3887">
                            <span class="fa-stack fa-lg">
                                <i class="fa fa-circle fa-stack-2x"></i>
                                <i class="fa fa-github fa-stack-1x fa-inverse"></i>
                            </span>
                        </a>
                    </li>
		    
                    
                    <li>
                        <a target="_blank" href="https://www.linkedin.com/in/lupeier">
                            <span class="fa-stack fa-lg">
                                <i class="fa fa-circle fa-stack-2x"></i>
                                <i class="fa fa-linkedin fa-stack-1x fa-inverse"></i>
                            </span>
                        </a>
                    </li>
		    
                </ul>
		<p class="copyright text-muted">
                    Copyright &copy; L&#39;s Blog , 2019
                    <br>
                    <br>
                    <a href="http://icp.chinaz.com/info?q=lupeier.com" target="_blank">备案号：沪ICP备19022667号-1</a>                    
                </p>
            </div>
        </div>
    </div>
</footer>



<script>
    function async(u, c) {
      var d = document, t = 'script',
          o = d.createElement(t),
          s = d.getElementsByTagName(t)[0];
      o.src = u;
      if (c) { o.addEventListener('load', function (e) { c(null, e); }, false); }
      s.parentNode.insertBefore(o, s);
    }
</script>






<script>
    
    if($('#tag_cloud').length !== 0){
        async("/js/jquery.tagcloud.js",function(){
            $.fn.tagcloud.defaults = {
                
                color: {start: '#bbbbee', end: '#0085a1'},
            };
            $('#tag_cloud a').tagcloud();
        })
    }
</script>


<script>
    async("/js/fastclick.js", function(){
        var $nav = document.querySelector("nav");
        if($nav) FastClick.attach($nav);
    })
</script>


<script>
    (function(){
        var bp = document.createElement('script');
        var curProtocol = window.location.protocol.split(':')[0];
        if (curProtocol === 'https'){
       bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
      }
      else{
      bp.src = 'http://push.zhanzhang.baidu.com/push.js';
      }
        var s = document.getElementsByTagName("script")[0];
        s.parentNode.insertBefore(bp, s);
    })();
</script>







</body>
</html>
